package com.jidong.test_springboot.config;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.Filter;

import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;//这是一个大坑，一定要手动引用
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import com.jidong.test_springboot.shiro.JWTFilter;


@Configuration  //凡是有这个注解的类我们认为是springboot配置类，springboot会优先加载
public class ShiroConfig {

	//SecurityManager 传参 类型应该是shiro包内的，而不是java.lang里的
	@Bean  //这个方法是创建factoryBean的。需要注入一个参数。
	public ShiroFilterFactoryBean shiroFilter(SecurityManager sm) {
		ShiroFilterFactoryBean sfb=new ShiroFilterFactoryBean();
		//把SecurityManager给factoryBean
		sfb.setSecurityManager(sm);
		
		//添加拦截链
		Map<String,String> map=new LinkedHashMap<String,String>();
		
		map.put("/user/login.do", "anon");//key是一个具体地址，value是验证该地址是否有该权限  如果有权限就放行，没权限 就跳转到noLogin或noAuth
		//anon是shiro规定一个关键字，不能瞎写，也不能写错， 指 不拦截该请求
		map.put("/user/reigst.do", "anon");
		map.put("/noAuth.do", "anon");
		map.put("/favicon.ico", "anon");
//		map.put("/dept/list.do", "perms[dept:list]");
//		//当用户访问dept/list.do的时候，必须具体dept:list权限，如果不具备会自动跳转到 noAuth.do
//		//perms[] 是shiro规定的一个关键字，不能瞎写，[   ]内部可以写多个权限，多个权限用逗号隔开，每个权限用引号引起来 单个权限不用引号
//		map.put("/dept/update.do", "perms[dept:update]");
//		map.put("/dept/delete.do", "perms[dept:delete]");
//		map.put("/dept/add.do", "perms[dept:add]");
		//perms内部写的权限是跟数据库的信息匹配的，如果没匹配上认为没有权限
		
//		map.put("/user/list.do", "roles[guanliyuan]");
//		map.put("/user/update.do", "roles[guanliyuan]");
//		map.put("/user/delete.do", "roles[guanliyuan]");
		
		Map<String,Filter> filters=new HashMap();
		filters.put("jwt", new JWTFilter());
		sfb.setFilters(filters);//把自定义的过滤器交给ShiroFilterFactoryBean 这样就能用
		
		map.put("/**", "jwt");
		sfb.setFilterChainDefinitionMap(map);
		
	
		//所有请求都必须通过登录验证，如果没有登录就跳转到noLogin.do
		//以上所有拦截从上往下依次执行，/**这句话必须写在所有的拦截最下面，否则会都不通过。
		
		//设置没有登录的跳转  如果没有登录就跳转到noLogin请求
//		sfb.setLoginUrl("/noLogin.do"); authc用到这句话。现在 这句话没有用了，因为登录验证的拦截器改为我们自己的了 。现在是以异常抛出
		//设置没有权限的跳转  
//		sfb.setUnauthorizedUrl("/noAuth.do"); perms用到这句话，现在没有用了，因为我们虽然也验证了权限，但是改为了注解方式，不走这里了。现在是以异常抛出
		return sfb;
	}

	//这个方法需要一个参数，参数是realm，会自动从Spring容器中寻找。这个realm是我们自己定义的，需要用Component注解交给spring
	@Bean("securityManager")  //这个方法是创建一个SecurityManager的bean，给上面的factoryBean使用
	public DefaultWebSecurityManager sm(AuthorizingRealm realm) {
		DefaultWebSecurityManager sm=new DefaultWebSecurityManager();
		//把realm设置给sm，Realm封装了登录逻辑和权限判断逻辑
		sm.setRealm(realm);
		/*
		 * 关闭shiro自带的session，详情见文档
		 * http://shiro.apache.org/session-management.html#SessionManagement-
		 * StatelessApplications%28Sessionless%29
		 */
		DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
		DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
		defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
		subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
		sm.setSubjectDAO(subjectDAO);
		return sm;
	}
	
	
	
	/**
	 * 下面的代码是添加注解支持
	 * @return
	 */
	@Bean
	@DependsOn("lifecycleBeanPostProcessor")
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
		defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
		return defaultAdvisorAutoProxyCreator;
	}

	@Bean
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
		advisor.setSecurityManager(securityManager);
		return advisor;
	}
	

}
